package com.cui.project.manager;


import com.api.common.common.ErrorCode;
import com.cui.project.exception.BusinessException;
import com.cui.project.model.entity.InterfaceTrafficForecast;
import com.cui.project.service.InterfaceTrafficForecastService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Date;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 动态智能限流管理器
 *
 * 核心思想：
 * 1. 根据流量预测动态调整限流阈值
 * 2. 低峰期放宽限制，高峰期收紧限制
 * 3. 避免"一刀切"的固定限流
 *
 * 业务价值：
 * - 提升用户体验：低峰期不限流
 * - 保障系统稳定：高峰期精准限流
 * - 资源利用最大化
 *
 * @author cui
 */
@Service
@Slf4j
public class DynamicRateLimiterManager {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Resource
    private InterfaceTrafficForecastService forecastService;

    /**
     * 基础限流阈值（保底值）
     */
    private static final int BASE_RATE_LIMIT = 100; // 100 QPS

//    private static final String RATE_LIMIT_KEY="api:rate_limit:dynamic:%s";

    // 更新 Redis Hash 结构（供网关读取）
    private static final String RATE_LIMIT_KEY="api:rate_limit:config:%s";
    private static final String RATE_LIMITER_KEY="api:rate_limiter:interface:%s:user:%s";

    /**
     * 定时更新动态限流配置（每5分钟执行一次）
     *
     * 根据未来1小时的流量预测，动态调整各接口的限流阈值
     */
    @Scheduled(cron = "0 */5 * * * ?")
    public void updateDynamicRateLimits() {
        log.info("开始更新动态限流配置");

        //1.查询未来1小时的流量预测
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime oneHourLater = now.plus(1, ChronoUnit.HOURS);


        List<InterfaceTrafficForecast> forecasts = forecastService.lambdaQuery()
                .between(InterfaceTrafficForecast::getForecastTime,
                        Date.from(now.atZone(ZoneId.systemDefault()).toInstant()),
                        Date.from(oneHourLater.atZone(ZoneId.systemDefault()).toInstant())
                ).list();

        //2.为每个接口计算动态限流阈值。3600=1小时，
        for (InterfaceTrafficForecast forecast : forecasts) {
            Long interfaceInfoId = forecast.getInterfaceInfoId();
            int predictedQps=forecast.getForecastRequestCount()/3600;

            //3.计算动态限流阈值
            int dynamicRateLimit=calculateDynamicRateLimit(
                    predictedQps,
                    forecast.getConfidenceLower() / 3600,
                    forecast.getConfidenceUpper() / 3600
            );

            // 4. 更新Redis中的限流配置
            String configKey = String.format(RATE_LIMIT_KEY, interfaceInfoId);
//            Map<String, Object> config = new HashMap<>();
//            config.put("replenishRate", dynamicRateLimit);
//            config.put("burstCapacity", dynamicRateLimit * 1.3);  // 突发容量为30%
//            redisTemplate.opsForHash().putAll(configKey,config);

            redisTemplate.opsForHash().put(configKey, "replenishRate", dynamicRateLimit);
            redisTemplate.opsForHash().put(configKey, "burstCapacity", (int)(dynamicRateLimit * 1.4));

            log.info("接口 {} 动态限流更新: 预测QPS={}, 限流阈值={}",
                    interfaceInfoId, predictedQps, dynamicRateLimit);
        }

    }

    /**
     * 智能限流执行
     *
     * @param interfaceId 接口ID
     * @param userId 用户ID
     */
    public void doSmartRateLimit(Long interfaceId, Long userId){
        // 1. 获取动态限流阈值
        String configKey = "rate_limit:dynamic:" + interfaceId;
        Integer dynamicLimit =(Integer) redisTemplate.opsForValue().get(configKey);

        // 如果没有预测数据，使用基础阈值
        int rateLimit=dynamicLimit!=null?dynamicLimit:BASE_RATE_LIMIT;

        // 2. VIP用户可享受1.5倍额度
        if (isVipUser(userId)) {
            rateLimit = (int) (rateLimit * 1.5);
        }

        //3.执行限流
        String limitKey = String.format(RATE_LIMITER_KEY, interfaceId, userId);
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(limitKey);
        rateLimiter.trySetRate(RateType.OVERALL,rateLimit,1, RateIntervalUnit.SECONDS);

        boolean acquire = rateLimiter.tryAcquire(1);
        if(!acquire){
            log.warn("触发动态限流: interfaceId={}, userId={}, limit={}",
                    interfaceId, userId, rateLimit);
            throw new BusinessException(ErrorCode.TOO_MANY_REQUEST,
                    "当前访问量较大，请稍后再试（预计" + rateLimit + "QPS）");
        }
    }
    /**
     * 计算动态限流阈值
     *
     * 策略：
     * 1. 使用置信区间上界作为限流阈值
     * 2. 预留10%缓冲空间
     * 3. 最低不低于基础阈值
     *
     * @param predictedQps 预测QPS
     * @param lowerBound 置信下界
     * @param upperBound 置信上界
     * @return 动态限流阈值
     */
    private int calculateDynamicRateLimit(int predictedQps, int lowerBound, int upperBound) {
        // 使用置信上界 + 10%缓冲
        int dynamicLimit=(int)(lowerBound*1.1);

        // 确保不低于基础阈值
        return Math.max(dynamicLimit,BASE_RATE_LIMIT);
    }


    /**
     * 判断是否为VIP用户
     */
    private boolean isVipUser(Long userId) {
        // TODO: 从数据库或缓存查询用户等级
        return false;
    }

}
